package com.iking.toolkit.util;

import com.iking.toolkit.model.Msg;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.util.UUID;

/**
 * 视频格式转换工具类（基于FFmpeg）
 */
@Slf4j
@Component
public class VideoConvertUtil {

    /**
     * 视频格式转换
     *
     * @param sourceFile   输入视频文件（MultipartFile）
     * @param targetFormat 目标格式（如mp4、avi、flv等，不含"."）
     * @return 转换后的视频文件（MultipartFile）
     */
    public static Msg<MultipartFile> convertVideo(MultipartFile sourceFile, String targetFormat) {
        File tempInputFile = null;
        File tempOutputFile = null;
        try {
            // 校验输入
            if (sourceFile.isEmpty()) {
                return Msg.fail("输入文件为空");
            }
            if (targetFormat == null || targetFormat.trim().isEmpty()) {
                return Msg.fail("目标格式不能为空");
            }
            targetFormat = targetFormat.toLowerCase();
            // 1. 创建临时文件（输入和输出）
            tempInputFile = createTempFile(sourceFile.getOriginalFilename());
            tempOutputFile = createTempFile(UUID.randomUUID() + "." + targetFormat);

            // 2. 将MultipartFile写入临时输入文件
            sourceFile.transferTo(tempInputFile);

            // 3. 调用FFmpeg进行格式转换
            boolean convertSuccess = ffmpegConvert(tempInputFile.getAbsolutePath(), tempOutputFile.getAbsolutePath());
            if (!convertSuccess) {
                return Msg.fail("视频格式转换失败");
            }
            // 4. 将临时输出文件转换为MultipartFile
            MultipartFile multipartFile = fileToMultipartFile(tempOutputFile, sourceFile.getOriginalFilename().replaceAll("\\.[^.]+$", "") + "." + targetFormat);
            log.info("视频转换成功：{} -> {}，大小：{} bytes",
                    sourceFile.getOriginalFilename(), multipartFile.getOriginalFilename(), multipartFile.getSize());
            return Msg.sucess(multipartFile);

        } catch (Exception e) {
            log.error("视频格式转换异常！", e);
            return Msg.fail("视频格式转换异常!");
        } finally {
            // 5. 清理临时文件
            deleteTempFile(tempInputFile);
            deleteTempFile(tempOutputFile);
        }
    }

    /**
     * 调用FFmpeg进行格式转换
     *
     * @param inputPath  输入文件路径
     * @param outputPath 输出文件路径
     * @return 是否转换成功
     */
    private static boolean ffmpegConvert(String inputPath, String outputPath) throws Exception {
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;

        try {
            grabber = new FFmpegFrameGrabber(inputPath);
            grabber.start();

            // 1. 解析目标格式（从输出路径后缀获取）
            String targetFormat = outputPath.substring(outputPath.lastIndexOf(".") + 1).toLowerCase();
            // 2. 获取原视频参数
            int width = grabber.getImageWidth();
            int height = grabber.getImageHeight();
            int audioChannels = grabber.getAudioChannels();
            double frameRate = grabber.getFrameRate();
            int originalVideoBitrate = grabber.getVideoBitrate();
            int originalAudioBitrate = grabber.getAudioBitrate();
            int sampleRate = grabber.getSampleRate();

            // 3. 初始化录制器
            recorder = new FFmpegFrameRecorder(outputPath, width, height, audioChannels);

            // 4. 根据目标格式动态配置编码器和参数
            if ("webm".equals(targetFormat)) {
                // ===== WebM格式配置（仅支持VP8/VP9视频 + Vorbis/Opus音频）=====
                // 视频编码器：VP8（兼容性更好）或VP9（高质量）
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_VP8);
                // WebM支持CRF（范围0-63，30-40为平衡值）
                recorder.setOption("crf", "35");
                recorder.setFrameRate(frameRate);
                recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); // 强制兼容像素格式

                // 音频编码器：Vorbis（WebM标准）
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_VORBIS);
                recorder.setAudioBitrate(originalAudioBitrate > 0 ? originalAudioBitrate : 128000); // 默认128kbps
                recorder.setSampleRate(sampleRate > 0 ? sampleRate : 44100);

                // WebM专用参数
                recorder.setFormat("webm");
                recorder.setOption("cpu-used", "1"); // 编码速度（0-8，值小质量高）

            } else if ("mpg".equals(targetFormat) || "mpeg".equals(targetFormat)) {
                // 视频编码器：MPEG-2专用
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG2VIDEO);
                // 固定比特率（避免原参数异常）
                int videoBitrate = originalVideoBitrate > 0 ? originalVideoBitrate : 6000000;
                recorder.setVideoBitrate(videoBitrate);
                recorder.setFrameRate(frameRate);
                recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
                boolean hasAudio = audioChannels > 0 && sampleRate > 0;
                // 处理音频（关键修改）
                if (hasAudio) {
                    // 优先使用MP3编码器（兼容性更好）
                    recorder.setAudioCodec(avcodec.AV_CODEC_ID_MP3);
                    // 强制标准音频参数
                    recorder.setAudioBitrate(128000);
                    recorder.setSampleRate(44100);
                } else {
                    // 无音频时禁用音频编码
                    recorder.setAudioCodec(avcodec.AV_CODEC_ID_NONE);
                }

                // 简化格式配置
                recorder.setFormat("mpeg");

            } else {
                // ===== 现有格式（如MP4、FLV等）配置（H.264 + AAC）=====
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
                recorder.setVideoBitrate(originalVideoBitrate > 0 ? originalVideoBitrate : 2000000); // 原比特率或默认2Mbps
                recorder.setFrameRate(frameRate);

                // 近无损配置
                recorder.setOption("crf", "18");
                recorder.setOption("preset", "veryslow");
                recorder.setOption("profile:v", "high");
                recorder.setOption("tune", "film");
                recorder.setOption("flags", "+bitexact");

                // 音频配置
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setAudioBitrate(originalAudioBitrate > 0 ? originalAudioBitrate : 128000);
                recorder.setSampleRate(sampleRate > 0 ? sampleRate : 44100);

                // 格式设置（如FLV、MP4等）
                recorder.setFormat(targetFormat);
            }

            // 5. 启动录制器并处理帧
            recorder.start();
            Frame frame;
            while ((frame = grabber.grabFrame()) != null) {
                recorder.record(frame);
            }

            return true;
        } catch (Exception e) {
            throw new RuntimeException("FFmpeg转换失败（格式：" +
                    outputPath.substring(outputPath.lastIndexOf(".") + 1) + "）：" + e.getMessage(), e);
        } finally {
            // 释放资源
            if (recorder != null) {
                try { recorder.stop(); recorder.release(); } catch (Exception e) { e.printStackTrace(); }
            }
            if (grabber != null) {
                try { grabber.stop(); grabber.release(); } catch (Exception e) { e.printStackTrace(); }
            }
        }
    }


    /**
     * 创建临时文件
     */
    private static File createTempFile(String fileName) throws IOException {
        String tempDir = System.getProperty("java.io.tmpdir");
        File tempFile = new File(tempDir, UUID.randomUUID() + "_" + fileName);
        if (!tempFile.exists()) {
            tempFile.createNewFile();
        }
        return tempFile;
    }

    /**
     * File转换为MultipartFile
     */
    private static MultipartFile fileToMultipartFile(File file, String originalFilename) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        return new MockMultipartFile(
                "file",
                originalFilename,
                Files.probeContentType(file.toPath()), // 自动识别MIME类型
                fis
        );
    }

    /**
     * 删除临时文件
     */
    private static void deleteTempFile(File file) {
        if (file != null && file.exists() && !file.delete()) {
            System.err.println("临时文件删除失败：" + file.getAbsolutePath());
        }
    }
}
